# -*- coding: utf-8 -*-
"""
Created on Sat Dec 29 23:03:15 2012

@author: Winand
"""

#Currently supported template features:
#%extend "<filename>"%
#   extend another template with %block directives content, other content will
#   be ignored, directive must be placed at the beginning of a file
#%block <name> [<text> kcolb]%
#   multiline text <text> replaces content of block <name> in file specified
#   in %extend directive, value of a block in base file means it's default
#   value, if value <text> is not specified that means empty value
#%include "<filename>"%
#   include another file
#%<fieldname>%
#   insert given integer, string or string list values* in template, if list
#   is provided, it's values will be inserted at according %for iterations
#%for <count> <text> rof%
#   repeat multiline text <text> <count> times

from __future__ import with_statement
if __name__ == '__main__': import sys; sys.path.append("C:\\WinPython-32bit-2.7.3.2\\projects\\lancomm")
from cgi import escape
from general import localPath
import re
from settings import TEMPLATEDIR
from webapi.log import debug, error
from webapi.server.remotedict import RemoteDict
template_cache = RemoteDict("templates")
deps = [] #circular dependencies watcher

AJAX_HANDLER_JS_FUNC = "loadAjaxChunk"
AJAX_LOADING_ICON = "/static/images/ajax_loading.gif"

#def __extendParent(name, fields):
#    #EXTEND
#    result, last, include_count = "", 0, 0
#    html = template_cache[name]
#    m = re.match(r'%extend\s+"(.+?)"\s*%', html)
#    if not m: return #no parent template 
#    base = template(m.group(1), fields)
#    result, blocks, last = [], {}, 0
##    print '---'
#    for m in re.finditer(r'%block\s+(\S+?)(?:\s(.+?)\skcolb|\s*)%', base, re.DOTALL):
##        print 'base', m.groups()
#        result.append(base[last:m.start()])
#        result.append(m.group(2) or "")
#        blocks[m.group(1)] = len(result)-1 
#        last = m.end()
#    result.append(base[last:])
##    print '---'
#    for m in re.finditer(r'%block\s+(\S+?)(?:\s(.+?)\skcolb|\s*)%', html, re.DOTALL):
##        print name, m.groups()
#        blocki=blocks.get(m.group(1))
#        if blocki: result[blocki] = m.group(2) or "" #replace default
#    template_cache[name] = "".join(result)

def __loadInlineFields(html, name):
    fields = {}
    result, last = [], 0
    for m in re.finditer(r'%var\s+(\S+?)\s(.+?)\srav%', html, re.DOTALL):
        fields[m.group(1)] = m.group(2)
        result.append(html[last:m.start()])
        last = m.end()
    result.append(html[last:])
    result_s = "".join(result)
    for field, value in fields.items():
        result_s = result_s.replace("%"+field+"%", value)
    return result_s

def __loadIncludes(html, name, fields):
    if name not in deps: deps.append(name)
    else:
        error('Circular dependency detected at', name, 'in', deps[-1])
        return ''
    #INCLUDES
    result, last = [], 0
    for m in re.finditer(r'%include\s+"(.+?)(?:\|(\S+?))*"\s*%', html):
        result.extend([html[last:m.start()], \
                                __getHtml(m.group(1), fields, m.group(2))])
        last = m.end()
    result.append(html[last:])
    deps.pop() #remove from deps watcher
    return "".join(result)
    
def __extractBlock(html, blockname):
    #TODO: do we need empty blocks?
    for m in re.finditer(r'%block(?:_ajax)?\s+(\S+?)\s(.+?)\skcolb%', html, re.DOTALL):
        if m.group(1) != blockname: continue
        return m.group(2) or ""

#Load template and cache it
def __getHtml(name, fields, blockname=None):
    if name not in template_cache:
        try:
            with open(localPath(TEMPLATEDIR+name)) as f:
                html = f.read()
#                __extendParent(name, fields) #load parent
                html = __loadIncludes(html, name, fields) #load includes
                html = __loadInlineFields(html, name)
                template_cache[name] = html
                debug('Template', name, 'loaded')
        except IOError: error("Cannot read template", name)
    html = template_cache.get(name, '')
    if blockname: html = __extractBlock(html, blockname)
    return html

def __setIterFields(i, text, fields):
    #ITERATOR FIELDS
    ret=text
    for field, value in fields.items():
        if type(value) is not str and len(value)>i: #replace list fields here
            ret = ret.replace("%"+field+"%", value[i])
    return ret

def template(name, fields={}, blockname=None):
    with template_cache:
        html = __getHtml(name, fields, blockname)
        
        #FIELDS
        for field, value in fields.items():
            if type(value) is str: #replace string fields here
                html = html.replace("%"+field+"%", value)
        #ITERATORS
        result, last = [], 0
        for i, m in enumerate(re.finditer(r'%for\s+(\d+)\s(.+?)\srof%', html, re.DOTALL)):
            iters=int(m.group(1))
            text=m.group(2)
            result.extend([html[last:m.start()], \
                ''.join([__setIterFields(i,text,fields) for i in range(iters)])])
            last = m.end()
        result.append(html[last:])
        html = "".join(result)
        
        #Cut out blocks, generate ajax code
        if not blockname: #hide blocks if there're any
            result, last = [], 0
            for m in re.finditer(r'%block(_ajax)?\s+(\S+?)\s(.+?)\skcolb%', html, re.DOTALL):
                result.append(html[last:m.start()])
                if m.group(1) != None: #ajax block
                    result.append('<div id="'+m.group(2)+'"><img src="'+AJAX_LOADING_ICON+'"><script>'+AJAX_HANDLER_JS_FUNC+'("'+fields.get("srv_name", "%srv_name%")+'","'+ \
                                m.group(2)+'")</script></div>')
                last = m.end()
            result.append(html[last:])
            html = "".join(result)
                
        return html

if __name__ == '__main__':
    print template("test.html")
